/*
 * =====================================================================================
 *
 *       Filename:  test_signal_hdlr.cxx
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  03/29/2011 03:15:03 AM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Chen Ken (Ken), zlchen.ken@gmail.com
 *        Company:  EMC
 *
 * =====================================================================================
 */

#include <execinfo.h>
#include <iostream>
#include <memory>
#include <functional>
#include "cl_signal_handler.hxx"
#include "cl_thread.hxx"
#include "cl_singleton.hxx"

using namespace std;
using namespace neo;

class SignalCallback
{
public:
	SignalCallback(const string& service)
		: m_service(service)
	{
		init();
		installSignalHandler();
    m_thr = unique_ptr<CLThread>(new CLThread(bind(&SignalCallback::doJob, this)));
	}

	void start(void)
	{
	  m_thr->start();
	}

  void whenSegFault(void) 
	{
    FILE* pf = fopen("signal_handler.crash", "a");
    if(pf != NULL)
    {
      int fd = fileno(pf);
      string s("Stack trace for the offending thread:\n"); 
      fwrite(s.c_str(), 1, s.size(), pf);
      fflush(pf);
      void* arr[80];
      int siz = backtrace(arr, 80);
      backtrace_symbols_fd(arr, siz, fd);
    }
	}

	void whenHup(void) 
	{
		cout << "Hup\n";
	}

	void whenUser1(void) 
	{
		cout << "User1\n";
	}

	void whenUser2(void) 
	{
		cout << "User2\n";
	}

	void whenAbort(void) 
	{
		cout << "Abort\n";
		exit(0);
	}

	void whenInterrupt(void) 
	{
		cout << "Interrupt\n";
	}

	void whenTermination(void) 
	{
		cout << "Termination\n";
	}

	void whenPipe(void) 
	{
		cout << "Pipe\n";
	}

	void whenFPE(void) 
	{
		cout << "FPE\n";
	}

	void whenStop(void) 
	{
		cout << "Stop\n";
	}

	void doJob(void)
	{
		for(;;)
		{
			pause();
		}
	}

private:
	void installSignalHandler(void)
	{
    map<string, CallbackFunc>::iterator itr = m_callbacks.find(m_service);   
		if(itr != m_callbacks.end())
		{
      if(!CLSingleton<CLSignalHandler>::instance()->installHandlerFor(m_sigs[m_service], 
					bind(itr->second, this)))
			{
				cout << "install signal handler for " << m_service << "failed\n"; 
			}
		}
	}

	void init(void)
	{
    m_callbacks["print"] = &SignalCallback::whenHup; 
    m_callbacks["mail"] = &SignalCallback::whenUser1; 
    m_callbacks["watchdog"] = &SignalCallback::whenSegFault; 
    m_callbacks["timer"] = &SignalCallback::whenInterrupt; 
    m_callbacks["keepalive"] = &SignalCallback::whenAbort; 
    m_callbacks["checker"] = &SignalCallback::whenStop; 
    m_callbacks["cleaner"] = &SignalCallback::whenPipe; 

		m_sigs["print"] = SIGHUP;
		m_sigs["mail"] = SIGUSR1; 
		m_sigs["watchdog"] = SIGSEGV; 
		m_sigs["timer"] = SIGINT; 
		m_sigs["keepalive"] = SIGABRT; 
		m_sigs["checker"] = SIGSEGV; 
		m_sigs["cleaner"] = SIGPIPE; 
	}

private:
	typedef void (SignalCallback::*CallbackFunc)(void);
	map<string, CallbackFunc> m_callbacks;
	map<string, int> m_sigs;
	unique_ptr<CLThread> m_thr;
	string m_service;
};

int main(int argc, char* argv[])
{
  CLSingleton<CLSignalHandler>::create();

  SignalCallback printer("print");
  SignalCallback mailer("mail");
  SignalCallback watchdog("watchdog");
  SignalCallback timer("timer");
  SignalCallback checker("checker");
  SignalCallback cleaner("cleaner");
  SignalCallback keepalive("keepalive");

	cout << "wait for signals\n";
	CLSingleton<CLSignalHandler>::instance()->waitForSignal();

	printer.start();
	mailer.start();
	watchdog.start();
	keepalive.start();
	timer.start();
	checker.start();
	cleaner.start();

	for(;;)
	{
		sleep(2);
		int* p = NULL;
		*p = 0;
		pause();
	}
}

